/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package br.great.functionalCore;

import java.util.Iterator;
import java.util.Vector;
import java.util.logging.Level;
import java.util.logging.Logger;
//import javax.xml.parsers.ParserConfigurationException;
import br.great.beans.*;
import br.great.exception.*;
import com.hp.hpl.jena.query.*;
import com.hp.hpl.jena.rdf.model.*;
import java.io.*;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import org.w3c.dom.*;
import org.xml.sax.InputSource;
import java.util.regex.*;
import java.util.Date;

/**
 *
 * @author C�line DEFAUT
 */
public class CollectionValidator {

    private static CollectionValidator instance;
    private String dossier;
    private double minX = 0,  minY = 0,  maxX = 0,  maxY = 0;

    private CollectionValidator() {
    }

    public static CollectionValidator getInstance() {
        if (instance == null) {
            instance = new CollectionValidator();
        }
        return instance;
    }

    private String getDossier(String uriColl) {
        int i = uriColl.lastIndexOf("\\");
        if (i >= 0) {
            return uriColl.substring(0, i + 1);
        } else {
            return null;
        }
    }

    /*
     *open a local collection
     *parameter : uri
     *              the local URI of the collection's ontology
     */
    public Collection openCollection(String uri) throws InvalidCollectionException {
        Collection coll = new Collection();
        FileInputStream in;
        try {
            this.dossier = getDossier(uri);

            // opening ontology
            in = new FileInputStream(uri);
            Model model = ModelFactory.createMemModelMaker().createModel();
            model.read(in, null);
            in.close();

            // creation of the Collection, with his name, uri, content annotation (tags and textual description), 
            createCollection(coll, uri, model);

            trackList(coll, model);
        } catch (Exception ex) {
            ex.printStackTrace();
        }
        return coll;
    }

    public void trackList(Collection coll, Model model) {
        try {
            String queryTrackList = "PREFIX j.1:<http://www.georss.org/georss/> PREFIX time:<http://www.w3.org/2006/time#> PREFIX ctxtphoto:<http://www-lsr.imag.fr/users/Windson.Viana/ontologies/ContextPhoto.owl#> SELECT ?coor ?time WHERE { ?coll ctxtphoto:hasTrackList ?list. ?list ctxtphoto:hasTrackPoint ?point. ?point j.1:point ?coor. ?point time:inXSDDateTime ?time }";
            Query query = QueryFactory.create(queryTrackList);
            QueryExecution qe = QueryExecutionFactory.create(query, model);
            ResultSet results = qe.execSelect();
            String xml = ResultSetFormatter.asXMLString(results);
//            System.out.println(xml);

            DocumentBuilder parser = DocumentBuilderFactory.newInstance().newDocumentBuilder();
            Document document = parser.parse(new InputSource(new StringReader(xml)));
            Element root = (Element) document.getDocumentElement();
//            walkDOMBranch(root);

            Vector<TrackPoint> trackList = getTrackList(root);
            coll.setTrackPointList(trackList);
            Point p = new Point();

            // for have the center of the collection
            Iterator it = trackList.iterator();
            while (it.hasNext()) {
                TrackPoint t = (TrackPoint) it.next();
                double lat = t.getLatitude();
                double lng = t.getLongitude();
                if (lat < minX) {
                    minX = lat;
                } else if (lat > maxX) {
                    maxX = lat;
                }
                if (lng < minY) {
                    minY = lng;
                } else if (lng > maxY) {
                    maxY = lng;
                }
            }
            p.setLatitude((maxX + minX) / 2);
            p.setLongitude((maxY + minY) / 2);
            coll.setCenterCollection(p);
        } catch (Exception ex) {
            Logger.getLogger(CollectionValidator.class.getName()).log(Level.SEVERE, null, ex);
        }
    }

    /**
     *create a Collection 
     */
    private void createCollection(Collection coll, String uri, Model model) {
        coll.setURI(uri);
        try {
            String queryContentAnnotation = "PREFIX j.1:<http://www.georss.org/georss/> PREFIX time:<http://www.w3.org/2006/time#> PREFIX ctxtphoto:<http://www-lsr.imag.fr/users/Windson.Viana/ontologies/ContextPhoto.owl#>  SELECT DISTINCT ?annotation ?tag ?coll ?photo ?dateB ?dateE ?coor ?time ?list {{?coll a ctxtphoto:Event_Collection} UNION {?contentAnnotation ctxtphoto:textual_description ?annotation} UNION {?contentAnnotation ctxtphoto:tag ?tag } UNION {?c ctxtphoto:photo ?photo } UNION {?col time:hasBeginning ?begin. ?begin time:inXSDDateTime ?dateB} UNION {?col time:hasEnd ?end. ?end time:inXSDDateTime ?dateE}UNION {?collection ctxtphoto:hasTrackList ?list.?list ctxtphoto:hasTrackPoint ?point.?point j.1:point ?coor.?point time:inXSDDateTime ?time}}";
            Query query1 = QueryFactory.create(queryContentAnnotation);
            QueryExecution qe1 = QueryExecutionFactory.create(query1, model);
            ResultSet results1 = qe1.execSelect();
            String xml = ResultSetFormatter.asXMLString(results1);
//            System.out.println(xml);

            DocumentBuilder parser = DocumentBuilderFactory.newInstance().newDocumentBuilder();
            Document document = parser.parse(new InputSource(new StringReader(xml)));
            Element root = (Element) document.getDocumentElement();
//            walkDOMBranch(root);

            String begin = getBegin(root);
//            System.out.println("begin : "+begin);
            Date b = constructDate(begin);
//            System.out.println("day : "+b.getDate());
            coll.setBegin(b);

            String end = getEnd(root);
//            System.out.println("end : "+end);
            Date e = constructDate(end);
//            System.out.println("day : "+e.getDate());
            coll.setEnd(e);

            String id = getAbout(root);
            coll.setAbout(getURL(id));
            coll.setName(getValue(id));

            String textualDescription = getTextualDescription(root);
            coll.setContentAnnotation(textualDescription);

            Vector<Tag> tags = getTags(root);
            coll.setTags(tags);

            Vector<Photo> photos = getPhotos(root);
            if (photos.size() <= 0) {
                throw new InvalidCollectionException();
            }
            coll.setPhotos(photos);
//            walkDOMBranch(root);
        } catch (Exception ex) {
            ex.printStackTrace();
        }
    }

    private Vector<TrackPoint> getTrackList(Node node) {
        Vector<TrackPoint> trackList = new Vector<TrackPoint>();
        String nodeName = node.getNodeName();
        if (nodeName.equals("result")) {
            TrackPoint trackPoint = new TrackPoint();
            Point point = null;
            Date date = null;
            NodeList nodeList = node.getChildNodes();
            int size = nodeList.getLength();
            for (int i = 0; i < size; i++) {
                Node bind = nodeList.item(i);
                if (bind.getNodeName().equals("binding")) {
                    NamedNodeMap nnm = bind.getAttributes();
                    Node attribut = nnm.getNamedItem("name");
                    // get coor of TrackPoint
                    if (attribut != null) {
                        if ((attribut != null) && (attribut.getNodeValue() != null) && (attribut.getNodeValue().equals("coor"))) {
                            if (bind.hasChildNodes()) {
                                NodeList nodeListCoor = bind.getChildNodes();
                                int s = nodeListCoor.getLength();
                                for (int j = 0; j < s; j++) {
                                    Node l = nodeListCoor.item(j);
                                    if (l.getNodeName().equals("literal")) {
                                        Node c = l.getFirstChild();
                                        point = getCoordinate(c.getNodeValue());
//                                    System.out.println("coor : "+c.getNodeValue());
                                    }
                                }
                            }
                        }
                    }
                    // get date of TrackPoint
                    if (attribut != null && (attribut.getNodeValue() != null) && attribut.getNodeValue().equals("time")) {
                        if (bind.hasChildNodes()) {
                            NodeList nodeListCoor = bind.getChildNodes();
                            int s = nodeListCoor.getLength();
                            for (int j = 0; j < s; j++) {
                                Node l = nodeListCoor.item(j);
                                if (l.getNodeName().equals("literal")) {
                                    Node c = l.getFirstChild();
                                    date = constructDate(c.getNodeValue());
//                                    System.out.println("date : "+c.getNodeValue());
                                }
                            }
                        }
                    }
                }
            }
            if (date != null && point != null) {
                trackPoint.setDateTime(date);
                trackPoint.setLatitude(point.getLatitude());
                trackPoint.setLongitude(point.getLongitude());
                trackList.add(trackPoint);
            }
        }

        if (node.hasChildNodes()) {
            NodeList nodeList = node.getChildNodes();
            int size = nodeList.getLength();
            for (int i = 0; i < size; i++) {
                Vector<TrackPoint> res = getTrackList(nodeList.item(i));
                if (res.size() > 0) {
                    trackList.addAll(res);
                }
            }
        }

        return trackList;
    }

    private static Point getCoordinate(String point) {
        Point coor = null;
        int index = point.indexOf(" ");
        if (index > 0) {
            coor = new Point();
            double lat = Double.parseDouble(point.substring(0, index));
            coor.setLatitude(lat);
            double lon = Double.parseDouble(point.substring(index + 1));
            coor.setLongitude(lon);
        }
        return coor;
    }

    private String getBegin(Node node) {
        String nodeName = node.getNodeName();
        if (nodeName.equals("binding")) {
            //System.out.println("value binding : "+node.getNodeValue());
            NamedNodeMap nnm = node.getAttributes();
            Node n = nnm.getNamedItem("name");
            //System.out.println("value name : "+n.getNodeValue());
            if ((n != null) && (n.getNodeValue().equals("dateB"))) {
                if (node.hasChildNodes()) {
                    NodeList nodeListAnnot = node.getChildNodes();
                    int size = nodeListAnnot.getLength();
                    for (int i = 0; i < size; i++) {
                        Node l = nodeListAnnot.item(i);
                        if (l.getNodeName().equals("literal")) {
                            Node c = l.getFirstChild();
                            return c.getNodeValue();
                        }
                    }
                }
            }
        }

        if (node.hasChildNodes()) {
            NodeList nodeList = node.getChildNodes();
            int size = nodeList.getLength();
            for (int i = 0; i < size; i++) {
                String res = getBegin(nodeList.item(i));
                if (res != null) {
                    return res;
                }
            }
        }

        return null;
    }

    private String getEnd(Node node) {
        String nodeName = node.getNodeName();
        if (nodeName.equals("binding")) {
            //System.out.println("value binding : "+node.getNodeValue());
            NamedNodeMap nnm = node.getAttributes();
            Node n = nnm.getNamedItem("name");
            //System.out.println("value name : "+n.getNodeValue());
            if ((n != null) && (n.getNodeValue().equals("dateE"))) {
                if (node.hasChildNodes()) {
                    NodeList nodeListAnnot = node.getChildNodes();
                    int size = nodeListAnnot.getLength();
                    for (int i = 0; i < size; i++) {
                        Node l = nodeListAnnot.item(i);
                        if (l.getNodeName().equals("literal")) {
                            Node c = l.getFirstChild();
                            return c.getNodeValue();
                        }
                    }
                }
            }
        }

        if (node.hasChildNodes()) {
            NodeList nodeList = node.getChildNodes();
            int size = nodeList.getLength();
            for (int i = 0; i < size; i++) {
                String res = getEnd(nodeList.item(i));
                if (res != null) {
                    return res;
                }
            }
        }
        return null;
    }

    private Date constructDate(String date) {
        Date d = null;
        Pattern p = Pattern.compile("([0-9]{4})-([0-9]{2})-([0-9]{2})T([0-9]{2}):([0-9]{2}):([0-9]{2})");
        Matcher m = p.matcher(date);
        if (m.matches()) {
            d = new Date(Integer.parseInt(m.group(1)) - 1900, Integer.parseInt(m.group(2)) - 1, Integer.parseInt(m.group(3)), Integer.parseInt(m.group(4)), Integer.parseInt(m.group(5)), Integer.parseInt(m.group(6)));
        }
        return d;
    }

    private static void walkDOMBranch(Node node) {
        // print the name and value (characters) of the Node
        System.out.println(node.getNodeName() + " : " + node.getNodeValue());
        if (node.getNodeType() == Node.ELEMENT_NODE) {
           // System.out.println(" : type = un �l�ment");
            NamedNodeMap nnm = node.getAttributes();
            int size = nnm.getLength();
          //  System.out.println("attributs : ");
            for (int i = 0; i < size; i++) {
                //System.out.print("  attribut " + i + " : ");
                System.out.println(nnm.item(i).getNodeName() + ":" + nnm.item(i).getNodeValue());
            }
        }
        //	if the node has children do the same thing for each child
        if (node.hasChildNodes()) {
            NodeList nodeList = node.getChildNodes();
            int size = nodeList.getLength();
            for (int i = 0; i < size; i++) {
                walkDOMBranch(nodeList.item(i));
            }
        }
    }

    private Vector<Tag> getTags(Node node) {
        Vector<Tag> tags = new Vector<Tag>();
        String nodeName = node.getNodeName();
        if (nodeName.equals("binding")) {
            //System.out.println("value binding : "+node.getNodeValue());
            NamedNodeMap nnm = node.getAttributes();
            Node n = nnm.getNamedItem("name");
            //System.out.println("value name : "+n.getNodeValue());
            if ((n != null) && (n.getNodeValue().equals("tag"))) {
                if (node.hasChildNodes()) {
                    NodeList nodeListAnnot = node.getChildNodes();
                    int size = nodeListAnnot.getLength();
                    for (int i = 0; i < size; i++) {
                        Node l = nodeListAnnot.item(i);
                        if (l.getNodeName().equals("literal")) {
                            Node c = l.getFirstChild();
                            Tag tag = new Tag();
                            tag.setTAG_VALUE(c.getNodeValue());
                            tags.add(tag);
                        }
                    }
                }
            }
        }

        if (node.hasChildNodes()) {
            NodeList nodeList = node.getChildNodes();
            int size = nodeList.getLength();
            for (int i = 0; i < size; i++) {
                Vector<Tag> res = getTags(nodeList.item(i));
                if (res.size() > 0) {
                    tags.addAll(res);
                }
            }
        }
        return tags;
    }

    private String getTextualDescription(Node node) {
        String nodeName = node.getNodeName();
        if (nodeName.equals("binding")) {
            //System.out.println("value binding : "+node.getNodeValue());
            NamedNodeMap nnm = node.getAttributes();
            Node n = nnm.getNamedItem("name");
            //System.out.println("value name : "+n.getNodeValue());
            if ((n != null) && (n.getNodeValue().equals("annotation"))) {
                if (node.hasChildNodes()) {
                    NodeList nodeListAnnot = node.getChildNodes();
                    int size = nodeListAnnot.getLength();
                    for (int i = 0; i < size; i++) {
                        Node l = nodeListAnnot.item(i);
                        if (l.getNodeName().equals("literal")) {
                            Node c = l.getFirstChild();
                            return c.getNodeValue();
                        }
                    }
                }
            }
        }

        if (node.hasChildNodes()) {
            NodeList nodeList = node.getChildNodes();
            int size = nodeList.getLength();
            for (int i = 0; i < size; i++) {
                String res = getTextualDescription(nodeList.item(i));
                if (res != null) {
                    return res;
                }
            }
        }

        return null;
    }

    private String getAbout(Node node) {
        String nodeName = node.getNodeName();
        if (nodeName.equals("binding")) {
            NamedNodeMap nnm = node.getAttributes();
            Node n = nnm.getNamedItem("name");
            if ((n != null) && (n.getNodeValue().equals("coll"))) {
                if (node.hasChildNodes()) {
                    NodeList nodeListAnnot = node.getChildNodes();
                    int size = nodeListAnnot.getLength();
                    for (int i = 0; i < size; i++) {
                        Node l = nodeListAnnot.item(i);
                        if (l.getNodeName().equals("uri")) {
                            Node c = l.getFirstChild();
                            return c.getNodeValue();
                        }
                    }
                }
            }
        }

        if (node.hasChildNodes()) {
            NodeList nodeList = node.getChildNodes();
            int size = nodeList.getLength();
            for (int i = 0; i < size; i++) {
                String res = getAbout(nodeList.item(i));
                if (res != null) {
                    return res;
                }
            }
        }
        return null;
    }

    private Vector<Photo> getPhotos(Node node) {
        Vector<Photo> photos = new Vector<Photo>();
        String nodeName = node.getNodeName();
        if (nodeName.equals("binding")) {
            NamedNodeMap nnm = node.getAttributes();
            Node n = nnm.getNamedItem("name");
            if ((n != null) && (n.getNodeValue().equals("photo"))) {
                if (node.hasChildNodes()) {
                    NodeList nodeListPhoto = node.getChildNodes();
                    int size = nodeListPhoto.getLength();
                    for (int i = 0; i < size; i++) {
                        Node l = nodeListPhoto.item(i);
                        if (l.getNodeName().equals("uri")) {
                            Node c = l.getFirstChild();
                            String about = c.getNodeValue();
                            String uri = this.dossier + getValue(about) + ".owl";
                            Photo photo = new Photo();
                            photo.setURIAnnotations(uri);
                            photo.setAbout(about);
                            photo.setName(getValue(about));
                            photos.add(photo);
                        }
                    }
                }
            }
        }

        if (node.hasChildNodes()) {
            NodeList nodeList = node.getChildNodes();
            int size = nodeList.getLength();
            for (int i = 0; i < size; i++) {
                Vector<Photo> res = getPhotos(nodeList.item(i));
                if (res.size() > 0) {
                    photos.addAll(res);
                }
            }
        }
        return photos;
    }

    /**
     * parameter about
     *          example : http://www-lsr.imag.fr/users/Windson.Viana/ontologies/romanForum1.owl#romanForum1
     *return 
     *          http://www-lsr.imag.fr/users/Windson.Viana/ontologies/romanForum1.owl
     */
    private static String getURL(String about) {
        String result = "";
        int indexFin = about.indexOf('#');
        if (indexFin >= 0) {
            result = about.substring(0, indexFin);
        }
        return result;
    }

    /**
     * parameter about
     *          example : http://www-lsr.imag.fr/users/Windson.Viana/ontologies/romanForum1.owl#romanForum
     *return 
     *          romanForum
     */
    private static String getValue(String about) {
        String result = "";
        int indexDeb = about.indexOf('#');
        if (indexDeb >= 0) {
            result = about.substring(indexDeb + 1);
        }
        return result;
    }
    /*public static void main(String[] args){
    System.out.println(getURI("http://www-lsr.imag.fr/users/Windson.Viana/ontologies/romanForum1.owl#romanForum1"));
    }*/
}
